package com.pentajock.docdb.colors;

import com.pentajock.docdb.dialogs.Dialogs;
import com.pentajock.docdb.images.DBImages;
import com.pentajock.docdb.lang.Lang;
import java.awt.Color;
import java.awt.Component;
//import java.lang.String;
import javax.swing.JColorChooser;
import javax.swing.JList;
import javax.swing.JTable;

/* For handling application colors */
public class Colors  {
	public static final Colors dueColor = new Colors(Lang.MISC.getText("COLOR_DUE", "Due Color"), Color.BLUE);
	public static final Colors alertColor = new Colors(Lang.MISC.getText("COLOR_ALERT", "Alert Color"), Color.RED);
	public static final Colors overDueColor = new Colors(Lang.MISC.getText("COLOR_OVERDUE", "Over-due Color"), Color.RED);
	public static final Colors defaultColor = new Colors(Lang.MISC.getText("COLOR_DEFAULT", "Default Color"), Color.BLACK);
	public static final Colors departmentColor = new Colors(Lang.MISC.getText("COLOR_DEPARTMENT", "Department Color"), Color.BLUE);
	
	public static final int DARKEN_COLOR_MODE = 4;
	public static final int LIGHTEN_COLOR_MODE = 2;
	public static final int ORIGINAL_COLOR_MODE = 1;
	
	public static int normalColorMode;
	public static int selectedColorMode;
	private static boolean refreshColors;
	
	private Color color;
	//private Color normalColor;
	private Color selectedColor;
	private Color lightenColor;
	private Color darkenColor;
	private String colorName;
	private String hex;
	private JColorChooser chooserPanel;
	
	/* Constructors */	
	public Colors(String colorName, Color color) {
		constructorHelper(colorName, color);
	}
	
	public Colors(String colorName) {
		constructorHelper(colorName, Color.BLUE);
	}
	
	public Colors() {
		constructorHelper("Sample Color", Color.BLUE);
	}

	private void constructorHelper(String colorName, Color color) {
		this.color = color;
		this.colorName = colorName;
		
		this.lightenColor = lightenColor(color);
		this.darkenColor = darkenColor(color);
		
		//this.normalColor = color;
		this.selectedColor = lightenColor;
		
		this.normalColorMode = ORIGINAL_COLOR_MODE;
		this.selectedColorMode = LIGHTEN_COLOR_MODE;
		
		this.hex = getHex(color);
		this.chooserPanel = new JColorChooser(color);
		
		this.refreshColors = true;
	}
	
	/* Methods */	
	public Color getColor() {
		return color;
	}
	
	public Color getColor(boolean isSelected) {
		return isSelected ? getSelectedColor() : getNormalColor();
	}
	
	public String getName() {
		return colorName;
	}
	
	public String getFixedName() {
		return colorName.toLowerCase().replaceAll(" ", "_");
	}
	
	public String toString() {
		return getName();
	}

	public void setColor(Color color) {
		this.color = color;
		this.lightenColor = lightenColor(color);
		this.darkenColor = darkenColor(color);
		this.hex = getHex(color);
		refreshColors = true;
	}
	
	public void setColor(String hex) {
		if (hex == null) return;
		try {
			Color color = Color.decode(hex);
			setColor(color);
		}
		catch (NumberFormatException e) {
			Dialogs.showError(e, this, Lang.DIALOG.getText("COLOR_ERROR", "Error loading color") + ": " + hex);
		}
	}
	
	public void setName(String colorName) {
		this.colorName = colorName;
	}
	
	/* Return the hex value of the color for use with HTML */
	public String getHex() {
		return hex;
	}
	
	public static String getHex(Color c) {
		String hex = Integer.toHexString(c.getRGB());
		return ("#" + hex.substring(2, hex.length())).toUpperCase();
	}

	private Color getNormalColor() {
		switch (normalColorMode) {
			case DARKEN_COLOR_MODE:		return darkenColor;
			case LIGHTEN_COLOR_MODE:	return lightenColor;
			case ORIGINAL_COLOR_MODE:	return color;
			default:			return color;
		}
	}
	
	private Color getSelectedColor() {
		switch (selectedColorMode) {
			case DARKEN_COLOR_MODE:		return darkenColor;
			case LIGHTEN_COLOR_MODE:	return lightenColor;
			case ORIGINAL_COLOR_MODE:	return color;
			default:			return lightenColor;
		}
	}
	
	public static void setSelectedColorMode(int selectedColorMode) {
		Colors.selectedColorMode = selectedColorMode;
	}
	
	public static void setNormalColorMode(int normalColorMode) {
		Colors.normalColorMode = normalColorMode;
	}
	
	public void showDialog() {
		showDialog(null);
	}
	
	public void showDialog(Component c) {
		Color color = null;
		color = chooserPanel.showDialog(c, colorName, color);
		if (color == null) 
			return;
		else if (getName().equals(dueColor.getName())) 
			dueColor.setColor(color);
		else if (getName().equals(alertColor.getName())) 
			alertColor.setColor(color);
		else if (getName().equals(overDueColor.getName())) 
			overDueColor.setColor(color);
		else if (getName().equals(defaultColor.getName())) 
			defaultColor.setColor(color);
		else if (getName().equals(departmentColor.getName())) 
			departmentColor.setColor(color);
	}
	
	/* Lightens Color - Divides saturation by 5, making it 80% lighter */
	public static Color lightenColor(Color c) {
		float[] hsb = Color.RGBtoHSB(c.getRed(), c.getGreen(), c.getBlue(), null);
		return new Color(Color.HSBtoRGB(hsb[0], hsb[1] / 5f, hsb[2])); 
	}
	
	/* Darkens Color - Divides brightness by 1.5, making it 33% darker */
	public static Color darkenColor(Color c) {
		float[] hsb = Color.RGBtoHSB(c.getRed(), c.getGreen(), c.getBlue(), null);
		return new Color(Color.HSBtoRGB(hsb[0], hsb[1], hsb[2]  / 1.5f)); 
	}
	
	public static float getBrightness(Color c) {
		return Color.RGBtoHSB(c.getRed(), c.getGreen(), c.getBlue(), null)[2];
	}
	
	public static float getHue(Color c) {
		return Color.RGBtoHSB(c.getRed(), c.getGreen(), c.getBlue(), null)[0];
	}
	
	public static float getSaturation(Color c) {
		return Color.RGBtoHSB(c.getRed(), c.getGreen(), c.getBlue(), null)[1];
	}
	
	/* Darkens / Lightens the application colors to accomodate the theme
	 * 	Example: A selected item in the "Metal" theme looks crappy if blue 
	 *	text is lightened, but the Windows theme looks crappy if the text
	 *	is darkened.  This auto-adjusts based on color brightness.
	 */
	public static void deriveBestColors(Object j) {
		if (refreshColors) {
			float selected;
			float normal;
			DBImages.resetAlertIcons();
			if (j instanceof JList) {
				JList i = (JList)j;
				selected =  getBrightness(i.getSelectionBackground());
				normal =  getBrightness(i.getBackground());
			}
			else if (j instanceof JTable) {
				JTable i = (JTable)j;
				selected =  getBrightness(((JTable)j).getSelectionBackground());
				normal =  getBrightness(i.getBackground());
			}
			else
				return;
			
			float gray = 0.5f;
			
			if (selected > gray) // Selected > %50 brightness
				setSelectedColorMode(DARKEN_COLOR_MODE);
			else
				setSelectedColorMode(LIGHTEN_COLOR_MODE);
			
			if (normal > gray)  // Normal > %50 brightness
				setNormalColorMode(DARKEN_COLOR_MODE);
			else
				setNormalColorMode(LIGHTEN_COLOR_MODE);
			refreshColors = false;
		}
	}
	
	public static void refreshColors() {
		refreshColors = true;
	}
}
